#include "list.h"
#include "rbtree.h"
/*
#include "qmalloc.h"
*/

#include "rbtree_tpl.h"

#include "fastertpl.h"
#include "fastertpl_in.h"

char	g_FASTERTPL_VERSION_0_3_0[] = "0.3.0" ;
char	*g_FASTERTPL_VERSION = g_FASTERTPL_VERSION_0_3_0 ;

#define QMALLOC_ENABLE	0

#if QMALLOC_ENABLE
#define MALLOC	qmalloc
#define FREE	qfree
#define REALLOC	qrealloc
#define CALLOC	qcalloc
#define STRDUP	qstrdup
#define STRNDUP	qstrndup
#else
#define MALLOC	malloc
#define FREE	free
#define REALLOC	realloc
#define CALLOC	calloc
#define STRDUP	strdup
#define STRNDUP	strndup
#endif

#define _DEBUG		0

char		g_indent_str[] = "\t\t\t\t\t\t\t\t" ;
	
__thread int	g_last_error_line = 0 ;

#define FTClearLastErrorLine()		g_last_error_line=0

#define FTSetLastErrorLine()	{if(g_last_error_line==0)g_last_error_line=__LINE__;}

int FTGetLastErrorLine()
{
	return g_last_error_line;
}

#define CREATE_TEMPLATE_RETURN_NULL	{FTDestroyTemplate(tpl);FTSetLastErrorLine();return NULL;}

char *_FTGetTempatePieceData( struct FasterTempatePiece *piece )
{
	if( piece->type == FASTERTEMPLATEPIECETYPE_TEXT )
		return piece->data.text_data.p_text;
	else if( piece->type == FASTERTEMPLATEPIECETYPE_VAR )
		return piece->data.var_data.p_var_name;
	else if( piece->type == FASTERTEMPLATEPIECETYPE_SECTION )
		return piece->data.section_data.p_section_name;
	else if( piece->type == FASTERTEMPLATEPIECETYPE_DETAIL )
		return piece->data.detail_data.p_detail_name;
	else
		return NULL;
}

int _FTGetTempatePieceDataLength( struct FasterTempatePiece *piece )
{
	if( piece->type == FASTERTEMPLATEPIECETYPE_TEXT )
		return piece->data.text_data.text_len;
	else if( piece->type == FASTERTEMPLATEPIECETYPE_VAR )
		return piece->data.var_data.var_name_len;
	else if( piece->type == FASTERTEMPLATEPIECETYPE_SECTION )
		return piece->data.section_data.section_name_len;
	else if( piece->type == FASTERTEMPLATEPIECETYPE_DETAIL )
		return piece->data.detail_data.detail_name_len;
	else
		return -1;
}

void _FTTravelTemplate( struct FasterTempate *tpl )
{
	struct FasterTempatePiece	*tpl_piece = NULL ;
	
	list_for_each_entry( tpl_piece , & (tpl->tpl_piece_list) , struct FasterTempatePiece , tpl_piece_list_node )
	{
		if( tpl_piece->type == FASTERTEMPLATEPIECETYPE_TEXT )
		{
			printf( "FASTERTEMPLATEPIECETYPE_TEXT" );
			printf( " addr[%p] p_text[%.*s]" , tpl_piece , tpl_piece->data.text_data.text_len,tpl_piece->data.text_data.p_text );
			printf( "\n" );
		}
		else if( tpl_piece->type == FASTERTEMPLATEPIECETYPE_VAR )
		{
			printf( "FASTERTEMPLATEPIECETYPE_VAR" );
			printf( " addr[%p] var[%.*s] p_format[%.*s]" , tpl_piece , tpl_piece->data.var_data.var_name_len,tpl_piece->data.var_data.p_var_name , tpl_piece->data.var_data.format_len,tpl_piece->data.var_data.p_format );
			printf( "\n" );
		}
		else if( tpl_piece->type == FASTERTEMPLATEPIECETYPE_SECTION )
		{
			printf( "FASTERTEMPLATEPIECETYPE_SECTION" );
			printf( " addr[%p] section[%.*s]" , tpl_piece , tpl_piece->data.section_data.section_name_len,tpl_piece->data.section_data.p_section_name );
			if( tpl_piece->forward_piece )
			{
				printf( " <- forward_addr[%p] section[%.*s]" , tpl_piece->forward_piece , tpl_piece->forward_piece->data.section_data.section_name_len,tpl_piece->forward_piece->data.section_data.p_section_name );
			}
			if( tpl_piece->backward_piece )
			{
				printf( " -> backward_addr[%p] section[%.*s]" , tpl_piece->backward_piece , tpl_piece->backward_piece->data.section_data.section_name_len,tpl_piece->backward_piece->data.section_data.p_section_name );
			}
			printf( "\n" );
		}
		else if( tpl_piece->type == FASTERTEMPLATEPIECETYPE_DETAIL )
		{
			printf( "FASTERTEMPLATEPIECETYPE_DETAIL" );
			printf( " addr[%p] details[%.*s]" , tpl_piece , tpl_piece->data.detail_data.detail_name_len,tpl_piece->data.detail_data.p_detail_name );
			if( tpl_piece->forward_piece )
			{
				printf( " <- forward_addr[%p] details[%.*s]" , tpl_piece->forward_piece , tpl_piece->forward_piece->data.detail_data.detail_name_len,tpl_piece->forward_piece->data.detail_data.p_detail_name );
			}
			if( tpl_piece->backward_piece )
			{
				printf( " -> backward_addr[%p] details[%.*s]" , tpl_piece->backward_piece , tpl_piece->backward_piece->data.detail_data.detail_name_len,tpl_piece->backward_piece->data.detail_data.p_detail_name );
			}
			printf( "\n" );
		}
		else
		{
			printf( "*** ERROR : Unknow piece type[%d]\n" , tpl_piece->type );
		}
	}
	
	return;
}

struct FasterTempate *FTCreateTemplate( char *template_filename )
{
	struct FasterTempate		*tpl = NULL ;
	int				fd ;
	ssize_t				len ;
	char				*p0 = NULL ;
	char				*p1 = NULL ;
	char				*p = NULL ;
	struct FasterTempatePiece	*piece = NULL ;
	struct FasterTempatePiece	*p_travel_reverse_piece = NULL ;
#if _DEBUG
	int				depth = 0 ;
#endif
	
	FTClearLastErrorLine();
	
	tpl = (struct FasterTempate *)MALLOC( sizeof(struct FasterTempate) ) ;
	if( tpl == NULL )
		return NULL;
	memset( tpl , 0x00 , sizeof(struct FasterTempate) );
	
	INIT_LIST_HEAD( & (tpl->tpl_piece_list) );
	
	fd = open( template_filename , O_RDONLY ) ;
	if( fd == -1 )
	{
		CREATE_TEMPLATE_RETURN_NULL
	}
	
	tpl->file_length = lseek( fd , 0 , SEEK_END ) ;
	lseek( fd , 0 , SEEK_SET );
	
	tpl->file_content = (char*)MALLOC( tpl->file_length + 1 ) ;
	if( tpl->file_content == NULL )
	{
		close( fd );
		CREATE_TEMPLATE_RETURN_NULL
	}
	
	len = read( fd , tpl->file_content , tpl->file_length ) ;
	if( len < tpl->file_length )
	{
		close( fd );
		CREATE_TEMPLATE_RETURN_NULL
	}
	tpl->file_content[tpl->file_length] = '\0' ;
	
	close( fd );
	
	p = p0 = tpl->file_content ;
	while( (*p) )
	{
#if _DEBUG
printf( "PARSING %.*s[%c]\n" , depth,g_indent_str , (*p) );
#endif
		if( (*p) == '$' )
		{
#if _DEBUG
depth++;
#endif
			p++;
#if _DEBUG
printf( "PARSING %.*s[%c]\n" , depth,g_indent_str , (*p) );
#endif
			if( (*p) == '$' )
			{
#if _DEBUG
depth++;
#endif
				p++;
#if _DEBUG
printf( "PARSING %.*s[%c]\n" , depth,g_indent_str , (*p) );
#endif
				if( (*p) == '(' )
				{
					if( p0 < p-1 )
					{
						piece = (struct FasterTempatePiece *)MALLOC( sizeof(struct FasterTempatePiece) ) ;
						if( piece == NULL )
						{
							CREATE_TEMPLATE_RETURN_NULL
						}
						memset( piece , 0x00 , sizeof(struct FasterTempatePiece) );
						
						piece->type = FASTERTEMPLATEPIECETYPE_TEXT ;
						piece->data.text_data.p_text = p0 ;
						piece->data.text_data.text_len = p-2 - p0 ;
						list_add_tail( & (piece->tpl_piece_list_node) , & (tpl->tpl_piece_list) );
#if _DEBUG
printf( "ADD-TEXT %.*spiece[%p]\n" , depth,g_indent_str , piece );
#endif
					}
					
#if _DEBUG
depth++;
#endif
					p++;
					p0 = p ;
					p1 = NULL ;
					while( (*p) )
					{
						if( (*p) == ':' )
						{
							p++;
							p1 = p ;
						}
						else if( (*p) == ')' )
						{
#if _DEBUG
depth--;
#endif
#if _DEBUG
printf( "PARSING %.*s[%c]\n" , depth,g_indent_str , (*p) );
#endif
							piece = (struct FasterTempatePiece *)MALLOC( sizeof(struct FasterTempatePiece) ) ;
							if( piece == NULL )
							{
								CREATE_TEMPLATE_RETURN_NULL
							}
							memset( piece , 0x00 , sizeof(struct FasterTempatePiece) );
							
							piece->type = FASTERTEMPLATEPIECETYPE_VAR ;
							if( p1 == NULL )
							{
								piece->data.var_data.p_var_name = p0 ;
								piece->data.var_data.var_name_len = p - p0 ;
							}
							else
							{
								piece->data.var_data.p_var_name = p0 ;
								piece->data.var_data.var_name_len = p1-1 - p0 ;
								piece->data.var_data.p_format = p1 ;
								piece->data.var_data.format_len = p - p1 ;
							}
							list_add_tail( & (piece->tpl_piece_list_node) , & (tpl->tpl_piece_list) );
#if _DEBUG
printf( "ADD-VAR %.*spiece[%p] var[%.*s] p_format[%.*s]\n" , depth,g_indent_str , piece , piece->data.var_data.var_name_len,piece->data.var_data.p_var_name , piece->data.var_data.format_len,piece->data.var_data.p_format );
#endif
							
							p++;
#if _DEBUG
depth--;
#endif
#if _DEBUG
printf( "PARSING %.*s[%c]\n" , depth,g_indent_str , (*p) );
#endif
							
							p0 = p ;
							break;
						}
						else
						{
#if _DEBUG
printf( "PARSING %.*s[%c]\n" , depth,g_indent_str , (*p) );
#endif
							p++;
						}
					}
					if( (*p) == '\0' )
					{
						CREATE_TEMPLATE_RETURN_NULL
					}
				}
				else if( (*p) == '{' )
				{
#if _DEBUG
depth++;
#endif
					if( p0 < p-1 )
					{
						piece = (struct FasterTempatePiece *)MALLOC( sizeof(struct FasterTempatePiece) ) ;
						if( piece == NULL )
						{
							CREATE_TEMPLATE_RETURN_NULL
						}
						memset( piece , 0x00 , sizeof(struct FasterTempatePiece) );
						
						piece->type = FASTERTEMPLATEPIECETYPE_TEXT ;
						piece->data.text_data.p_text = p0 ;
						piece->data.text_data.text_len = p-2 - p0 ;
						list_add_tail( & (piece->tpl_piece_list_node) , & (tpl->tpl_piece_list) );
#if _DEBUG
printf( "ADD-TEXT %.*spiece[%p]\n" , depth,g_indent_str , piece );
#endif
					}
					
					p++;
					p0 = p ;
					while( (*p) )
					{
						if( (*p) == '/' )
						{
#if _DEBUG
depth--;
#endif
#if _DEBUG
printf( "PARSING %.*s[%c]\n" , depth,g_indent_str , (*p) );
#endif
							piece = (struct FasterTempatePiece *)MALLOC( sizeof(struct FasterTempatePiece) ) ;
							if( piece == NULL )
							{
								CREATE_TEMPLATE_RETURN_NULL
							}
							memset( piece , 0x00 , sizeof(struct FasterTempatePiece) );
							
							piece->type = FASTERTEMPLATEPIECETYPE_SECTION ;
							piece->data.section_data.p_section_name = p0 ;
							piece->data.section_data.section_name_len = p - p0 ;
							list_add_tail( & (piece->tpl_piece_list_node) , & (tpl->tpl_piece_list) );
#if _DEBUG
printf( "ADD-SECTION %.*spiece[%p] section[%.*s]\n" , depth,g_indent_str , piece , piece->data.section_data.section_name_len,piece->data.section_data.p_section_name );
#endif
							
							p++;
#if _DEBUG
depth--;
#endif
#if _DEBUG
printf( "PARSING %.*s[%c]\n" , depth,g_indent_str , (*p) );
#endif
							
							p0 = p ;
							break;
						}
						else
						{
#if _DEBUG
printf( "PARSING %.*s[%c]\n" , depth,g_indent_str , (*p) );
#endif
							p++;
						}
					}
					if( (*p) == '\0' )
					{
						CREATE_TEMPLATE_RETURN_NULL
					}
				}
				else if( (*p) == '[' )
				{
					if( p0 < p-1 )
					{
						piece = (struct FasterTempatePiece *)MALLOC( sizeof(struct FasterTempatePiece) ) ;
						if( piece == NULL )
						{
							CREATE_TEMPLATE_RETURN_NULL
						}
						memset( piece , 0x00 , sizeof(struct FasterTempatePiece) );
						
						piece->type = FASTERTEMPLATEPIECETYPE_TEXT ;
						piece->data.text_data.p_text = p0 ;
						piece->data.text_data.text_len = p-2 - p0 ;
						list_add_tail( & (piece->tpl_piece_list_node) , & (tpl->tpl_piece_list) );
#if _DEBUG
printf( "ADD-TEXT %.*spiece[%p]\n" , depth,g_indent_str , piece );
#endif
					}
					
#if _DEBUG
depth++;
#endif
					p++;
					p0 = p ;
					while( (*p) )
					{
						if( (*p) == '/' )
						{
#if _DEBUG
depth--;
#endif
#if _DEBUG
printf( "PARSING %.*s[%c]\n" , depth,g_indent_str , (*p) );
#endif
							piece = (struct FasterTempatePiece *)MALLOC( sizeof(struct FasterTempatePiece) ) ;
							if( piece == NULL )
							{
								CREATE_TEMPLATE_RETURN_NULL
							}
							memset( piece , 0x00 , sizeof(struct FasterTempatePiece) );
							
							piece->type = FASTERTEMPLATEPIECETYPE_DETAIL ;
							piece->data.detail_data.p_detail_name = p0 ;
							piece->data.detail_data.detail_name_len = p - p0 ;
							list_add_tail( & (piece->tpl_piece_list_node) , & (tpl->tpl_piece_list) );
#if _DEBUG
printf( "ADD-DETAILS %.*spiece[%p] details[%.*s]\n" , depth,g_indent_str , piece , piece->data.detail_data.detail_name_len,piece->data.detail_data.p_detail_name );
#endif
							
							p++;
#if _DEBUG
depth--;
#endif
#if _DEBUG
printf( "PARSING %.*s[%c]\n" , depth,g_indent_str , (*p) );
#endif
							
							p0 = p ;
							break;
						}
						else
						{
#if _DEBUG
printf( "PARSING %.*s[%c]\n" , depth,g_indent_str , (*p) );
#endif
							p++;
						}
					}
					if( (*p) == '\0' )
					{
						CREATE_TEMPLATE_RETURN_NULL
					}
				}
				else if( (*p) == '/' )
				{
					if( p0 < p-1 )
					{
						piece = (struct FasterTempatePiece *)MALLOC( sizeof(struct FasterTempatePiece) ) ;
						if( piece == NULL )
						{
							CREATE_TEMPLATE_RETURN_NULL
						}
						memset( piece , 0x00 , sizeof(struct FasterTempatePiece) );
						
						piece->type = FASTERTEMPLATEPIECETYPE_TEXT ;
						piece->data.text_data.p_text = p0 ;
						piece->data.text_data.text_len = p-2 - p0 ;
						list_add_tail( & (piece->tpl_piece_list_node) , & (tpl->tpl_piece_list) );
#if _DEBUG
printf( "ADD-TEXT %.*spiece[%p]\n" , depth,g_indent_str , piece );
#endif
					}
					
#if _DEBUG
depth++;
#endif
					p++;
					p0 = p ;
					while( (*p) )
					{
						if( (*p) == '}' )
						{
#if _DEBUG
depth--;
#endif
#if _DEBUG
printf( "PARSING %.*s[%c]\n" , depth,g_indent_str , (*p) );
#endif
							piece = (struct FasterTempatePiece *)MALLOC( sizeof(struct FasterTempatePiece) ) ;
							if( piece == NULL )
							{
								CREATE_TEMPLATE_RETURN_NULL
							}
							memset( piece , 0x00 , sizeof(struct FasterTempatePiece) );
							
							piece->type = FASTERTEMPLATEPIECETYPE_SECTION ;
							piece->data.detail_data.p_detail_name = p0 ;
							piece->data.detail_data.detail_name_len = p - p0 ;
							list_add_tail( & (piece->tpl_piece_list_node) , & (tpl->tpl_piece_list) );
#if _DEBUG
printf( "ADD-SECTION %.*spiece[%p] section[%.*s]\n" , depth,g_indent_str , piece , piece->data.detail_data.detail_name_len,piece->data.detail_data.p_detail_name );
#endif
							
							list_for_each_entry_reverse( p_travel_reverse_piece , & (tpl->tpl_piece_list) , struct FasterTempatePiece , tpl_piece_list_node )
							{
								if( p_travel_reverse_piece == piece )
									continue;
#if _DEBUG
printf( "BACKWARD %.*sp_travel_reverse_piece[%p]->type[%d] ->data[%.*s]\n" , depth,g_indent_str , p_travel_reverse_piece , p_travel_reverse_piece->type , _FTGetTempatePieceDataLength(p_travel_reverse_piece),_FTGetTempatePieceData(p_travel_reverse_piece) );
#endif
								if( p_travel_reverse_piece->type == FASTERTEMPLATEPIECETYPE_TEXT || p_travel_reverse_piece->type == FASTERTEMPLATEPIECETYPE_VAR )
									continue;
								
#if _DEBUG
printf( "BACKWARD %.*sp_travel_reverse_piece->backward_piece[%p]\n" , depth,g_indent_str , p_travel_reverse_piece->backward_piece );
#endif
								if( p_travel_reverse_piece->forward_piece || p_travel_reverse_piece->backward_piece )
									continue;
								
#if _DEBUG
printf( "BACKWARD %.*sp_travel_reverse_piece->type[%d] piece->type[%d]\n" , depth,g_indent_str , p_travel_reverse_piece->type , piece->type );
#endif
								if( p_travel_reverse_piece->type != piece->type )
									CREATE_TEMPLATE_RETURN_NULL
								
#if _DEBUG
printf( "BACKWARD %.*sp_travel_reverse_piece->type[%d] FASTERTEMPLATEPIECETYPE_SECTION[%d]\n" , depth,g_indent_str , p_travel_reverse_piece->type , FASTERTEMPLATEPIECETYPE_SECTION );
#endif
								if( p_travel_reverse_piece->type != FASTERTEMPLATEPIECETYPE_SECTION )
									CREATE_TEMPLATE_RETURN_NULL
								
#if _DEBUG
printf( "BACKWARD %.*sp_travel_reverse_piece->data.section_data.p_section_name[%.*s] piece->data.section_data.p_section_name[%.*s]\n" , depth,g_indent_str , p_travel_reverse_piece->data.section_data.section_name_len,p_travel_reverse_piece->data.section_data.p_section_name , piece->data.section_data.section_name_len,piece->data.section_data.p_section_name );
#endif
								if( p_travel_reverse_piece->data.section_data.section_name_len != piece->data.section_data.section_name_len || strncmp( p_travel_reverse_piece->data.section_data.p_section_name , piece->data.section_data.p_section_name , piece->data.section_data.section_name_len ) )
									CREATE_TEMPLATE_RETURN_NULL
								
								p_travel_reverse_piece->forward_piece = piece ;
								piece->backward_piece = p_travel_reverse_piece ;
#if _DEBUG
printf( "BACKWARD %.*sp_travel_reverse_piece[%p]->forward_piece[%p] <-> piece[%p]->backward_piece[%p]\n" , depth,g_indent_str , p_travel_reverse_piece,p_travel_reverse_piece->forward_piece , piece,piece->backward_piece );
#endif
								
								break;
							}
							if( & (p_travel_reverse_piece->tpl_piece_list_node) == & (tpl->tpl_piece_list) )
								CREATE_TEMPLATE_RETURN_NULL
							
							p++;
#if _DEBUG
depth--;
#endif
#if _DEBUG
printf( "PARSING %.*s[%c]\n" , depth,g_indent_str , (*p) );
#endif
							
							break;
						}
						else if( (*p) == ']' )
						{
#if _DEBUG
depth--;
#endif
#if _DEBUG
printf( "PARSING %.*s[%c]\n" , depth,g_indent_str , (*p) );
#endif
							piece = (struct FasterTempatePiece *)MALLOC( sizeof(struct FasterTempatePiece) ) ;
							if( piece == NULL )
							{
								CREATE_TEMPLATE_RETURN_NULL
							}
							memset( piece , 0x00 , sizeof(struct FasterTempatePiece) );
							
							piece->type = FASTERTEMPLATEPIECETYPE_DETAIL ;
							piece->data.detail_data.p_detail_name = p0 ;
							piece->data.detail_data.detail_name_len = p - p0 ;
							list_add_tail( & (piece->tpl_piece_list_node) , & (tpl->tpl_piece_list) );
#if _DEBUG
printf( "ADD-DETAILS %.*spiece[%p] details[%.*s]\n" , depth,g_indent_str , piece , piece->data.detail_data.detail_name_len,piece->data.detail_data.p_detail_name );
#endif
							
							list_for_each_entry_reverse( p_travel_reverse_piece , & (tpl->tpl_piece_list) , struct FasterTempatePiece , tpl_piece_list_node )
							{
								if( p_travel_reverse_piece == piece )
									continue;
#if _DEBUG
printf( "BACKWARD %.*sp_travel_reverse_piece[%p]->type[%d] ->data[%.*s]\n" , depth,g_indent_str , p_travel_reverse_piece , p_travel_reverse_piece->type , _FTGetTempatePieceDataLength(p_travel_reverse_piece),_FTGetTempatePieceData(p_travel_reverse_piece) );
#endif
								if( p_travel_reverse_piece->type == FASTERTEMPLATEPIECETYPE_TEXT || p_travel_reverse_piece->type == FASTERTEMPLATEPIECETYPE_VAR )
									continue;
								
#if _DEBUG
printf( "BACKWARD %.*sp_travel_reverse_piece->backward_piece[%p]\n" , depth,g_indent_str , p_travel_reverse_piece->backward_piece );
#endif
								if( p_travel_reverse_piece->forward_piece || p_travel_reverse_piece->backward_piece )
									continue;
								
#if _DEBUG
printf( "BACKWARD %.*sp_travel_reverse_piece->type[%d] piece->type[%d]\n" , depth,g_indent_str , p_travel_reverse_piece->type , piece->type );
#endif
								if( p_travel_reverse_piece->type != piece->type )
									CREATE_TEMPLATE_RETURN_NULL
								
#if _DEBUG
printf( "BACKWARD %.*sp_travel_reverse_piece->type[%d] FASTERTEMPLATEPIECETYPE_DETAIL[%d]\n" , depth,g_indent_str , p_travel_reverse_piece->type , FASTERTEMPLATEPIECETYPE_DETAIL );
#endif
								if( p_travel_reverse_piece->type != FASTERTEMPLATEPIECETYPE_DETAIL )
									CREATE_TEMPLATE_RETURN_NULL
								
#if _DEBUG
printf( "BACKWARD %.*sp_travel_reverse_piece->data.detail_data.p_detail_name[%.*s] piece->data.detail_data.p_detail_name[%.*s]\n" , depth,g_indent_str , p_travel_reverse_piece->data.detail_data.detail_name_len,p_travel_reverse_piece->data.detail_data.p_detail_name , piece->data.detail_data.detail_name_len,piece->data.detail_data.p_detail_name );
#endif

								if( p_travel_reverse_piece->data.detail_data.detail_name_len != piece->data.detail_data.detail_name_len || strncmp( p_travel_reverse_piece->data.detail_data.p_detail_name , piece->data.detail_data.p_detail_name , piece->data.detail_data.detail_name_len ) )
									CREATE_TEMPLATE_RETURN_NULL
								
								p_travel_reverse_piece->forward_piece = piece ;
								piece->backward_piece = p_travel_reverse_piece ;
#if _DEBUG
printf( "BACKWARD %.*sp_travel_reverse_piece[%p]->forward_piece[%p] <-> piece[%p]->backward_piece[%p]\n" , depth,g_indent_str , p_travel_reverse_piece,p_travel_reverse_piece->forward_piece , piece,piece->backward_piece );
#endif
								
								break;
							}
							if( & (p_travel_reverse_piece->tpl_piece_list_node) == & (tpl->tpl_piece_list) )
								CREATE_TEMPLATE_RETURN_NULL
							
							p++;
#if _DEBUG
depth--;
#endif
#if _DEBUG
printf( "PARSING %.*s[%c]\n" , depth,g_indent_str , (*p) );
#endif
							
							break;
						}
						else
						{
#if _DEBUG
printf( "PARSING %.*s[%c]\n" , depth,g_indent_str , (*p) );
#endif
							p++;
						}
					}
					
					p0 = p ;
				}
				else
				{
					p++;
				}
			}
			else
			{
				p++;
			}
		}
		else
		{
			p++;
		}
	}
	if( p0 < p )
	{
		piece = (struct FasterTempatePiece *)MALLOC( sizeof(struct FasterTempatePiece) ) ;
		if( piece == NULL )
		{
			CREATE_TEMPLATE_RETURN_NULL
		}
		memset( piece , 0x00 , sizeof(struct FasterTempatePiece) );
		
		piece->type = FASTERTEMPLATEPIECETYPE_TEXT ;
		piece->data.text_data.p_text = p0 ;
		piece->data.text_data.text_len = p-1 - p0 ;
		list_add_tail( & (piece->tpl_piece_list_node) , & (tpl->tpl_piece_list) );
#if _DEBUG
printf( "ADD-TEXT %.*spiece[%p]\n" , depth,g_indent_str , piece );
#endif
	}
	
#if _DEBUG
	printf( "---------------------------------------- _FTTravelTemplate\n" );
	_FTTravelTemplate( tpl );
#endif
	
	return tpl;
}

LINK_RBTREENODE_STRING_RETURNDUPLICATE( LinkFasterDataToTreeByName , struct FasterSection , datas_tree , struct FasterData , data_tree_node , name )
QUERY_RBTREENODE_STRING( QueryFasterDataFromTreeByName , struct FasterSection , datas_tree , struct FasterData , data_tree_node , name )
UNLINK_RBTREENODE( UnlinkFasterDataFromTreeNode , struct FasterSection , datas_tree , struct FasterData , data_tree_node )
TRAVEL_RBTREENODE( TravelFasterDatasTree , struct FasterSection , datas_tree , struct FasterData , data_tree_node )
funcFreeRbTreeNodeEntry FreeFasterDataTreeNodeEntry ;
void FreeFasterDataTreeNodeEntry( void *pv )
{
	struct FasterData	*data = (struct FasterData *) pv ;
	
	if( data->name )
	{
		FREE( data->name );
		data->name = NULL ;
	}
	
	if( data->type == FASTERDATATYPE_STRING )
	{
		FREE( data->data.str );
		data->data.str = NULL ;
	}
	
	FREE( data );
	
	return;
}
DESTROY_RBTREE( DestroyFasterDatasTree , struct FasterSection , datas_tree , struct FasterData , data_tree_node , & FreeFasterDataTreeNodeEntry )

LINK_RBTREENODE_STRING( LinkFasterDetailToTreeByDetailName , struct FasterSection , details_tree , struct FasterDetail , detail_tree_node , detail_name )
QUERY_RBTREENODE_STRING( QueryFasterDetailFromTreeByDetailName , struct FasterSection , details_tree , struct FasterDetail , detail_tree_node , detail_name )
UNLINK_RBTREENODE( UnlinkFasterDetailFromTreeNode , struct FasterSection , details_tree , struct FasterDetail , detail_tree_node )
TRAVEL_RBTREENODE( TravelFasterDetailsTree , struct FasterSection , details_tree , struct FasterDetail , detail_tree_node )
funcFreeRbTreeNodeEntry FreeFasterSectionTreeNodeEntry ;
funcFreeRbTreeNodeEntry FreeFasterDetailTreeNodeEntry ;
void FreeFasterDetailsTreeNodeEntry( void *pv )
{
	struct FasterDetail	*detail = (struct FasterDetail *) pv ;
	struct FasterSection	*p_section = NULL ;
	struct FasterSection	*p_next_section = NULL ;
	
	if( detail->detail_name )
	{
		FREE( detail->detail_name );
		detail->detail_name = NULL ;
	}
	
	list_for_each_entry_safe( p_section , p_next_section , & (detail->section_list) , struct FasterSection , section_list_node )
	{
		list_del( & (p_section->section_list_node) );
		
		FreeFasterSectionTreeNodeEntry( (void*)p_section );
	}
	
	FREE( detail );
	
	return;
}
DESTROY_RBTREE( DestroyFasterDetailsTree , struct FasterSection , details_tree , struct FasterDetail , detail_tree_node , & FreeFasterDetailsTreeNodeEntry )

LINK_RBTREENODE_STRING( LinkFasterSectionToTreeBySectionName , struct FasterSection , sub_section_tree , struct FasterSection , section_tree_node , section_name )
QUERY_RBTREENODE_STRING( QueryFasterSectionFromTreeBySectionName , struct FasterSection , sub_section_tree , struct FasterSection , section_tree_node , section_name )
UNLINK_RBTREENODE( UnlinkFasterSectionFromTreeNode , struct FasterSection , sub_section_tree , struct FasterSection , section_tree_node )
TRAVEL_RBTREENODE( TravelFasterSectionTree , struct FasterSection , sub_section_tree , struct FasterSection , section_tree_node )
void DestroyFasterSectionTree( struct FasterSection *section );
funcFreeRbTreeNodeEntry FreeFasterSectionTreeNodeEntry ;
void FreeFasterSectionTreeNodeEntry( void *pv )
{
	struct FasterSection	*section = (struct FasterSection *) pv ;
	
	if( section->section_name )
	{
		FREE( section->section_name );
		section->section_name = NULL ;
	}
	
	DestroyFasterDatasTree( section );
	
	DestroyFasterSectionTree( section );
	
	DestroyFasterDetailsTree( section );
	
	FREE( section );
	
	return;
}
DESTROY_RBTREE( DestroyFasterSectionTree , struct FasterSection , sub_section_tree , struct FasterSection , section_tree_node , & FreeFasterSectionTreeNodeEntry )

struct FasterSection *FTCreateSection( struct FasterSection *parent_section , char *section_name )
{
	struct FasterSection	*section = NULL ;
	
	int			nret = 0 ;
	
	section = (struct FasterSection *)MALLOC( sizeof(struct FasterSection) ) ;
	if( section == NULL )
		return NULL;
	memset( section , 0x00 , sizeof(struct FasterSection) );
	INIT_LIST_HEAD( & (section->section_list_node) );
	
	if( section_name )
	{
		section->section_name = STRDUP(section_name) ;
		if( section->section_name == NULL )
			return NULL;
	}
	
	if( parent_section )
	{
		nret = LinkFasterSectionToTreeBySectionName( parent_section , section ) ;
		if( nret )
		{
			FTDestroySection( section );
			return NULL;
		}
	}
	
	return section;
}

int FTSetShort( struct FasterSection *section , char *name , short s )
{
	struct FasterData	*data = NULL ;
	struct FasterData	*data_returnduplicate = NULL ;
	
	data = (struct FasterData *)MALLOC( sizeof(struct FasterData) ) ;
	if( data == NULL )
		return -1;
	memset( data , 0x00 , sizeof(struct FasterData) );
	
	data->name = STRDUP(name) ;
	if( data->name == NULL )
	{
		FREE( data );
		return -2;
	}
	data->type = FASTERDATATYPE_SHORT ;
	data->data.s = s ;
	
	data_returnduplicate = LinkFasterDataToTreeByName( section , data ) ;
	if( data_returnduplicate )
	{
		UnlinkFasterDataFromTreeNode( section , data_returnduplicate );
		FreeFasterDataTreeNodeEntry( (void*)data_returnduplicate );
		LinkFasterDataToTreeByName( section , data ) ;
	}
	
	return 0;
}

int FTSetInt( struct FasterSection *section , char *name , int i )
{
	struct FasterData	*data = NULL ;
	struct FasterData	*data_returnduplicate = NULL ;
	
	data = (struct FasterData *)MALLOC( sizeof(struct FasterData) ) ;
	if( data == NULL )
		return -1;
	memset( data , 0x00 , sizeof(struct FasterData) );
	
	data->name = STRDUP(name) ;
	if( data->name == NULL )
	{
		FREE( data );
		return -2;
	}
	data->type = FASTERDATATYPE_INT ;
	data->data.i = i ;
	
	data_returnduplicate = LinkFasterDataToTreeByName( section , data ) ;
	if( data_returnduplicate )
	{
		UnlinkFasterDataFromTreeNode( section , data_returnduplicate );
		FreeFasterDataTreeNodeEntry( (void*)data_returnduplicate );
		LinkFasterDataToTreeByName( section , data ) ;
	}
	
	return 0;
}

int FTSetLong( struct FasterSection *section , char *name , long l )
{
	struct FasterData	*data = NULL ;
	struct FasterData	*data_returnduplicate = NULL ;
	
	data = (struct FasterData *)MALLOC( sizeof(struct FasterData) ) ;
	if( data == NULL )
		return -1;
	memset( data , 0x00 , sizeof(struct FasterData) );
	
	data->name = STRDUP(name) ;
	if( data->name == NULL )
	{
		FREE( data );
		return -2;
	}
	data->type = FASTERDATATYPE_LONG ;
	data->data.l = l ;
	
	data_returnduplicate = LinkFasterDataToTreeByName( section , data ) ;
	if( data_returnduplicate )
	{
		UnlinkFasterDataFromTreeNode( section , data_returnduplicate );
		FreeFasterDataTreeNodeEntry( (void*)data_returnduplicate );
		LinkFasterDataToTreeByName( section , data ) ;
	}
	
	return 0;
}

int FTSetFloat( struct FasterSection *section , char *name , float f )
{
	struct FasterData	*data = NULL ;
	struct FasterData	*data_returnduplicate = NULL ;
	
	data = (struct FasterData *)MALLOC( sizeof(struct FasterData) ) ;
	if( data == NULL )
		return -1;
	memset( data , 0x00 , sizeof(struct FasterData) );
	
	data->name = STRDUP(name) ;
	if( data->name == NULL )
	{
		FREE( data );
		return -2;
	}
	data->type = FASTERDATATYPE_FLOAT ;
	data->data.f = f ;
	
	data_returnduplicate = LinkFasterDataToTreeByName( section , data ) ;
	if( data_returnduplicate )
	{
		UnlinkFasterDataFromTreeNode( section , data_returnduplicate );
		FreeFasterDataTreeNodeEntry( (void*)data_returnduplicate );
		LinkFasterDataToTreeByName( section , data ) ;
	}
	
	return 0;
}

int FTSetDouble( struct FasterSection *section , char *name , double d )
{
	struct FasterData	*data = NULL ;
	struct FasterData	*data_returnduplicate = NULL ;
	
	data = (struct FasterData *)MALLOC( sizeof(struct FasterData) ) ;
	if( data == NULL )
		return -1;
	memset( data , 0x00 , sizeof(struct FasterData) );
	
	data->name = STRDUP(name) ;
	if( data->name == NULL )
	{
		FREE( data );
		return -2;
	}
	data->type = FASTERDATATYPE_DOUBLE ;
	data->data.d = d ;
	
	data_returnduplicate = LinkFasterDataToTreeByName( section , data ) ;
	if( data_returnduplicate )
	{
		UnlinkFasterDataFromTreeNode( section , data_returnduplicate );
		FreeFasterDataTreeNodeEntry( (void*)data_returnduplicate );
		LinkFasterDataToTreeByName( section , data ) ;
	}
	
	return 0;
}

int FTSetChar( struct FasterSection *section , char *name , char ch )
{
	struct FasterData	*data = NULL ;
	struct FasterData	*data_returnduplicate = NULL ;
	
	data = (struct FasterData *)MALLOC( sizeof(struct FasterData) ) ;
	if( data == NULL )
		return -1;
	memset( data , 0x00 , sizeof(struct FasterData) );
	
	data->name = STRDUP(name) ;
	if( data->name == NULL )
	{
		FREE( data );
		return -2;
	}
	data->type = FASTERDATATYPE_CHAR ;
	data->data.ch = ch ;
	
	data_returnduplicate = LinkFasterDataToTreeByName( section , data ) ;
	if( data_returnduplicate )
	{
		UnlinkFasterDataFromTreeNode( section , data_returnduplicate );
		FreeFasterDataTreeNodeEntry( (void*)data_returnduplicate );
		LinkFasterDataToTreeByName( section , data ) ;
	}
	
	return 0;
}

int FTSetString( struct FasterSection *section , char *name , char *str )
{
	struct FasterData	*data = NULL ;
	struct FasterData	*data_returnduplicate = NULL ;
	
	data = (struct FasterData *)MALLOC( sizeof(struct FasterData) ) ;
	if( data == NULL )
		return -1;
	memset( data , 0x00 , sizeof(struct FasterData) );
	
	data->name = STRDUP(name) ;
	if( data->name == NULL )
	{
		FREE( data );
		return -2;
	}
	data->type = FASTERDATATYPE_STRING ;
	data->data.str = STRDUP(str) ;
	if( data->data.str == NULL )
	{
		FREE( data->name );
		FREE( data );
		return -3;
	}
	
	data_returnduplicate = LinkFasterDataToTreeByName( section , data ) ;
	if( data_returnduplicate )
	{
		UnlinkFasterDataFromTreeNode( section , data_returnduplicate );
		FreeFasterDataTreeNodeEntry( (void*)data_returnduplicate );
		LinkFasterDataToTreeByName( section , data ) ;
	}
	
	return 0;
}

int FTSetFormat( struct FasterSection *section , char *name , char *format , ... )
{
	struct FasterData	*data = NULL ;
	struct FasterData	*data_returnduplicate = NULL ;
	va_list			valist ;
	va_list			valist_bak ;
	int			len ;
	
	data = (struct FasterData *)MALLOC( sizeof(struct FasterData) ) ;
	if( data == NULL )
		return -1;
	memset( data , 0x00 , sizeof(struct FasterData) );
	
	data->name = STRDUP(name) ;
	if( data->name == NULL )
	{
		FREE( data );
		return -2;
	}
	data->type = FASTERDATATYPE_STRING ;
	va_start( valist , format );
	va_copy( valist_bak , valist );
	len = snprintf( NULL , 0 , format , valist ) ;
	va_end( valist );
	data->data.str = (char*)MALLOC( len+1 ) ;
	if( data->data.str == NULL )
	{
		FREE( data );
		return -3;
	}
	va_copy( valist , valist_bak );
	len = vsprintf( data->data.str , format , valist ) ;
	va_end( valist );
	if( len == -1 )
	{
		FREE( data->name );
		FREE( data );
		return -4;
	}
	
	data_returnduplicate = LinkFasterDataToTreeByName( section , data ) ;
	if( data_returnduplicate )
	{
		UnlinkFasterDataFromTreeNode( section , data_returnduplicate );
		FreeFasterDataTreeNodeEntry( (void*)data_returnduplicate );
		LinkFasterDataToTreeByName( section , data ) ;
	}
	
	return 0;
}

struct FasterSection *FTCreateDetail( struct FasterSection *parent_section , char *detail_name )
{
	struct FasterDetail	detail ;
	struct FasterDetail	*p_detail = NULL ;
	struct FasterSection	*p_section = NULL ;
	
	memset( & detail , 0x00 , sizeof(struct FasterDetail) );
	detail.detail_name = detail_name ;
	p_detail = QueryFasterDetailFromTreeByDetailName( parent_section , & detail ) ;
	if( p_detail == NULL )
	{
		p_detail = (struct FasterDetail *)MALLOC( sizeof(struct FasterDetail) ) ;
		if( p_detail == NULL )
			return NULL;
		memset( p_detail , 0x00 , sizeof(struct FasterDetail) );
		INIT_LIST_HEAD( & (p_detail->section_list) );
		
		p_detail->detail_name = STRDUP( detail_name ) ;
		
		LinkFasterDetailToTreeByDetailName( parent_section , p_detail );
	}
	
	p_section = FTCreateSection( NULL , NULL ) ;
	if( p_section == NULL )
	{
		return NULL;
	}
	
	list_add_tail( & (p_section->section_list_node) , & (p_detail->section_list) );
	
	return p_section;
}

static void _FTTravelFasterData( struct FasterData *data , int depth )
{
	printf( "TRAVEL-DATA     %.*stype[%d] name[%s]" , depth,g_indent_str , data->type , data->name );
	
	switch( data->type )
	{
		case FASTERDATATYPE_SHORT :
			printf( " short[%hd]\n" , data->data.s );
			break;
		case FASTERDATATYPE_INT :
			printf( " int[%d]\n" , data->data.i );
			break;
		case FASTERDATATYPE_LONG :
			printf( " long[%ld]\n" , data->data.l );
			break;
		case FASTERDATATYPE_FLOAT :
			printf( " float[%f]\n" , data->data.f );
			break;
		case FASTERDATATYPE_DOUBLE :
			printf( " double[%lf]\n" , data->data.d );
			break;
		case FASTERDATATYPE_CHAR :
			printf( " char[%c]\n" , data->data.ch );
			break;
		case FASTERDATATYPE_STRING :
			printf( " string[%s]\n" , data->data.str );
			break;
		default :
			printf( "*** ERROR : Unknow data type[%d]\n" , data->type );
			break;
	}
	
	return;
}

static void _FTTravelSection( struct FasterSection *section , int depth );
static void _FTTravelDetail( struct FasterDetail *p_detail , int depth )
{
	struct FasterSection	*p_section = NULL ;
	
	printf( "TRAVEL-DETAIL   %.*sdetail[%p] detail_name[%s]\n" , depth,g_indent_str , p_detail , p_detail->detail_name );
	
	list_for_each_entry( p_section , & (p_detail->section_list) , struct FasterSection , section_list_node )
	{
		_FTTravelSection( p_section , depth+1 );
	}
	
	return;
}

void _FTTravelSection( struct FasterSection *section , int depth )
{
	struct FasterData	*data = NULL ;
	struct FasterSection	*sub_section = NULL ;
	struct FasterDetail	*detail = NULL ;
	
	printf( "TRAVEL-SECTION  %.*ssection[%p] section_name[%s]\n" , depth,g_indent_str , section , section->section_name );
	
	data = NULL ;
	while(1)
	{
		data = TravelFasterDatasTree( section , data ) ;
		if( data == NULL )
			break;
		
		_FTTravelFasterData( data , depth+1 );
	}
	
	sub_section = NULL ;
	while(1)
	{
		sub_section = TravelFasterSectionTree( section , sub_section ) ;
		if( sub_section == NULL )
			break;
		
		_FTTravelSection( sub_section , depth+1 );
	}
	
	detail = NULL ;
	while(1)
	{
		detail = TravelFasterDetailsTree( section , detail ) ;
		if( detail == NULL )
			break;
		
		_FTTravelDetail( detail , depth+1 );
	}
	
	return;
}

static int _FTAppendInstancePieceList( struct list_head *p_instance_piece_list , int *p_str_piece_total_len , char *str_piece , int str_piece_len )
{
	struct FasterInstancePiece	*instance_piece = NULL ;
	
	instance_piece = (struct FasterInstancePiece *)MALLOC( sizeof(struct FasterInstancePiece) ) ;
	if( instance_piece == NULL )
		return -1;
	memset( instance_piece , 0x00 , sizeof(struct FasterInstancePiece) );
	
	instance_piece->str_piece = STRDUP(str_piece) ;
	if( instance_piece->str_piece == NULL )
	{
		FREE( instance_piece );
		return -2;
	}
	instance_piece->str_piece_len = str_piece_len ;
	
	list_add_tail( & (instance_piece->instance_piece_list_node) , p_instance_piece_list );
	
	(*p_str_piece_total_len) += str_piece_len ;
	
	return 0;
}

static int _FTInstanceSection( struct FasterTempatePiece *open_tpl_piece , struct FasterTempatePiece *close_tpl_piece , struct FasterSection *travel_section , struct list_head *p_instance_piece_list , int *p_str_piece_total_len )
{
	struct FasterTempatePiece	*tpl_piece = NULL ;
	
	int				nret = 0 ;
	
	tpl_piece = open_tpl_piece ;
	while(1)
	{
		if( tpl_piece->type == FASTERTEMPLATEPIECETYPE_TEXT )
		{
			nret = _FTAppendInstancePieceList( p_instance_piece_list , p_str_piece_total_len , tpl_piece->data.text_data.p_text , tpl_piece->data.text_data.text_len ) ;
			if( nret )
			{
				FTSetLastErrorLine();
				return nret;
			}
		}
		else if( tpl_piece->type == FASTERTEMPLATEPIECETYPE_VAR )
		{
			struct FasterData	data ;
			struct FasterData	*p_data = NULL ;
			char			*format = NULL ;
			char			buf[ 64 + 1 ] ;
			char			*p_buf = NULL ;
			int			len ;
			
			memset( & data , 0x00 , sizeof(struct FasterData) );
			data.name = STRNDUP( tpl_piece->data.var_data.p_var_name , tpl_piece->data.var_data.var_name_len ) ;
			p_data = QueryFasterDataFromTreeByName( travel_section , & data ) ;
			FREE( data.name );
			if( p_data )
			{
				if( tpl_piece->data.var_data.p_format )
				{
					format = STRNDUP( tpl_piece->data.var_data.p_format , tpl_piece->data.var_data.format_len ) ;
					if( format == NULL )
					{
						FTSetLastErrorLine();
						return -21;
					}
				}
				
				switch( p_data->type )
				{
					case FASTERDATATYPE_SHORT :
						memset( buf , 0x00 , sizeof(buf) );
						if( format == NULL )
							len = snprintf( buf , sizeof(buf)-1 , "%hd" , p_data->data.s ) ;
						else
							len = snprintf( buf , sizeof(buf)-1 , format , p_data->data.s ) ;
						p_buf = buf ;
						break;
					case FASTERDATATYPE_INT :
						memset( buf , 0x00 , sizeof(buf) );
						if( format == NULL )
							len = snprintf( buf , sizeof(buf)-1 , "%d" , p_data->data.i ) ;
						else
							len = snprintf( buf , sizeof(buf)-1 , format , p_data->data.i ) ;
						p_buf = buf ;
						break;
					case FASTERDATATYPE_LONG :
						memset( buf , 0x00 , sizeof(buf) );
						if( format == NULL )
							len = snprintf( buf , sizeof(buf)-1 , "%ld" , p_data->data.l ) ;
						else
							len = snprintf( buf , sizeof(buf)-1 , format , p_data->data.l ) ;
						p_buf = buf ;
						break;
					case FASTERDATATYPE_FLOAT :
						memset( buf , 0x00 , sizeof(buf) );
						if( format == NULL )
							len = snprintf( buf , sizeof(buf)-1 , "%f" , p_data->data.f ) ;
						else
							len = snprintf( buf , sizeof(buf)-1 , format , p_data->data.f ) ;
						p_buf = buf ;
						break;
					case FASTERDATATYPE_DOUBLE :
						memset( buf , 0x00 , sizeof(buf) );
						if( format == NULL )
							len = snprintf( buf , sizeof(buf)-1 , "%lf" , p_data->data.d ) ;
						else
							len = snprintf( buf , sizeof(buf)-1 , format , p_data->data.d ) ;
						p_buf = buf ;
						break;
					case FASTERDATATYPE_CHAR :
						p_buf = & (p_data->data.ch) ;
						len = 1 ;
						break;
					case FASTERDATATYPE_STRING :
						p_buf = p_data->data.str ;
						len = strlen(p_data->data.str) ;
						break;
					default :
						FTSetLastErrorLine();
						return -22;
				}
				
				if( format )
				{
					FREE(format); format = NULL ;
				}
				
				nret = _FTAppendInstancePieceList( p_instance_piece_list , p_str_piece_total_len , p_buf , len ) ;
				if( nret )
				{
					FTSetLastErrorLine();
					return nret;
				}
			}
		}
		else if( tpl_piece->type == FASTERTEMPLATEPIECETYPE_SECTION )
		{
			struct FasterSection	section ;
			struct FasterSection	*p_section = NULL ;
			
			memset( & section , 0x00 , sizeof(struct FasterSection) );
			section.section_name = STRNDUP( tpl_piece->data.section_data.p_section_name , tpl_piece->data.section_data.section_name_len ) ;
			p_section = QueryFasterSectionFromTreeBySectionName( travel_section , & section ) ;
			FREE( section.section_name );
			if( p_section )
			{
				nret = _FTInstanceSection( list_next_entry(tpl_piece,struct FasterTempatePiece,tpl_piece_list_node) , list_prev_entry(tpl_piece->forward_piece,struct FasterTempatePiece,tpl_piece_list_node) , p_section , p_instance_piece_list , p_str_piece_total_len ) ;
				if( nret )
				{
					FTSetLastErrorLine();
					return nret;
				}
			}
			
			tpl_piece = tpl_piece->forward_piece ;
		}
		else if( tpl_piece->type == FASTERTEMPLATEPIECETYPE_DETAIL )
		{
			struct FasterDetail	detail ;
			struct FasterDetail	*p_detail = NULL ;
			
			memset( & detail , 0x00 , sizeof(struct FasterDetail) );
			detail.detail_name = STRNDUP( tpl_piece->data.detail_data.p_detail_name , tpl_piece->data.detail_data.detail_name_len ) ;
			p_detail = QueryFasterDetailFromTreeByDetailName( travel_section , & detail ) ;
			FREE( detail.detail_name );
			if( p_detail )
			{
				struct FasterSection	*section_in_detail = NULL ;
				
				list_for_each_entry( section_in_detail , & (p_detail->section_list) , struct FasterSection , section_list_node )
				{
					nret = _FTInstanceSection( list_next_entry(tpl_piece,struct FasterTempatePiece,tpl_piece_list_node) , list_prev_entry(tpl_piece->forward_piece,struct FasterTempatePiece,tpl_piece_list_node) , section_in_detail , p_instance_piece_list , p_str_piece_total_len ) ;
					if( nret )
					{
						FTSetLastErrorLine();
						return nret;
					}
				}
			}
			
			tpl_piece = tpl_piece->forward_piece ;
		}
		else
		{
			FTSetLastErrorLine();
			return -1;
		}
		
		if( tpl_piece == close_tpl_piece )
			break;
		
		tpl_piece = list_next_entry( tpl_piece , struct FasterTempatePiece , tpl_piece_list_node ) ;
	}
	
	return 0;
}

char *FTInstantiateTemplate( struct FasterTempate *tpl , struct FasterSection *section )
{
	struct list_head		instance_piece_list ;
	int				str_piece_total_len ;
	
	struct FasterInstancePiece	*p_instance_piece = NULL ;
	struct FasterInstancePiece	*p_next_instance_piece = NULL ;
	char				*p = NULL ;
	
	int				nret = 0 ;
	
	FTClearLastErrorLine();
	
#if _DEBUG
	printf( "---------------------------------------- _FTTravelSection\n" );
	_FTTravelSection( section , 0 );
#endif	
	
	INIT_LIST_HEAD( & (instance_piece_list) );
	str_piece_total_len = 0 ;
	nret = _FTInstanceSection( list_first_entry(&(tpl->tpl_piece_list),struct FasterTempatePiece,tpl_piece_list_node) , list_last_entry(&(tpl->tpl_piece_list),struct FasterTempatePiece,tpl_piece_list_node) , section , & instance_piece_list , & str_piece_total_len ) ;
	if( nret )
	{
		FTSetLastErrorLine();
		goto _ERROR;
	}
	
#if _DEBUG
	{
	int	check_total_len = 0 ;
	list_for_each_entry( p_instance_piece , & instance_piece_list , struct FasterInstancePiece , instance_piece_list_node )
	{
		printf( "INSTANCE-PIECE [%d][%.*s]\n" , p_instance_piece->str_piece_len , p_instance_piece->str_piece_len,p_instance_piece->str_piece );
		check_total_len += p_instance_piece->str_piece_len ;
	}
	printf( "INSTANCE-PIECE TOTAL-LENGTH[%d] CHECK-LENGTH[%d]\n" , str_piece_total_len , check_total_len );
	}
#endif

#if _DEBUG
printf( "tpl->instance_buffer[%p] tpl->instance_buffer_size[%d]\n" , tpl->instance_buffer , tpl->instance_buffer_size );
printf( "str_piece_total_len[%d]\n" , str_piece_total_len );
#endif
	if( tpl->instance_buffer == NULL || tpl->instance_buffer_size-1 < str_piece_total_len )
	{
		char	*tmp = NULL ;
		int	new_instance_buffer_size ;
		
		new_instance_buffer_size = str_piece_total_len+1 ;
		tmp = (char*)REALLOC( tpl->instance_buffer , new_instance_buffer_size ) ;
		if( tmp == NULL )
		{
			FTSetLastErrorLine();
			goto _ERROR;
		}
		tpl->instance_buffer = tmp ;
		tpl->instance_buffer_size = new_instance_buffer_size ;
#if _DEBUG
printf( "AFTER ALLOC tpl->instance_buffer[%p] tpl->instance_buffer_size[%d]\n" , tpl->instance_buffer , tpl->instance_buffer_size );
#endif
	}
	
	memset( tpl->instance_buffer , 0x00 , str_piece_total_len+1 );
	p = tpl->instance_buffer ;
	list_for_each_entry_safe( p_instance_piece , p_next_instance_piece , & instance_piece_list , struct FasterInstancePiece , instance_piece_list_node )
	{
#if _DEBUG
printf( "APPEND[%ld][%.*s]\n" , p-tpl->instance_buffer , p_instance_piece->str_piece_len,p_instance_piece->str_piece );
#endif
		memcpy( p , p_instance_piece->str_piece , p_instance_piece->str_piece_len );
		p += p_instance_piece->str_piece_len ;
		
		if( p_instance_piece->str_piece )
			FREE( p_instance_piece->str_piece );
		
		FREE( p_instance_piece );
	}
	
	return tpl->instance_buffer;

_ERROR :
	
	list_for_each_entry_safe( p_instance_piece , p_next_instance_piece , & instance_piece_list , struct FasterInstancePiece , instance_piece_list_node )
	{
		if( p_instance_piece->str_piece )
			FREE( p_instance_piece->str_piece );
		
		FREE( p_instance_piece );
	}
	
	return NULL;
}

void FTDestroySection( struct FasterSection *section )
{
	if( section )
	{
		FreeFasterSectionTreeNodeEntry( (void*)section );
	}
	
	return;
}

void FTDestroyTemplate( struct FasterTempate *tpl )
{
	struct FasterTempatePiece	*p_piece = NULL ;
	struct FasterTempatePiece	*p_next_piece = NULL ;
	
	if( tpl->file_content )
		FREE( tpl->file_content );
	
	list_for_each_entry_safe( p_piece , p_next_piece , & (tpl->tpl_piece_list) , struct FasterTempatePiece , tpl_piece_list_node )
	{
		list_del( & (p_piece->tpl_piece_list_node) );
		FREE( p_piece );
	}
	
	if( tpl->instance_buffer )
	{
		FREE( tpl->instance_buffer );
	}
	
	FREE( tpl );
	
	return;
}

